import { ContentType, type Content } from '../../types/document'
import {
  buildContentKey,
  RECENT_DOCUMENTS_KEY,
  STORAGE_META_KEY,
  STORAGE_PREFIX
} from './storageKeys'
import {
  type RecentContentEntry,
  type StorageAdapter,
  type StorageResult,
  type StorageError,
  type StorageUsageSummary,
  type ContentListItem,
  StorageErrorCode
} from './types'
import { createStorageError, mapExceptionToStorageError } from './storageErrors'

const STORAGE_VERSION = 1
const SAVED_BY = 'local'
const DEFAULT_RECENT_LIMIT = 10
const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/
const DATE_KEYS = new Set([
  'createdAt',
  'updatedAt',
  'lastAIEditAt',
  'lastRunAt',
  'nextRunAt',
  'start',
  'end'
])

type SerializableContent = Omit<Content, 'createdAt' | 'updatedAt'> & {
  createdAt: string
  updatedAt: string
}

type StoredContentEnvelope = {
  id: string
  type: ContentType
  version: number
  payload: SerializableContent
  metadata: {
    savedAt: string
    savedBy: string
  }
}

const isLocalStorageAvailable = (): boolean => {
  if (typeof window === 'undefined') {
    return false
  }

  try {
    const testKey = '__rmzf_storage_test__'
    window.localStorage.setItem(testKey, '1')
    window.localStorage.removeItem(testKey)
    return true
  } catch (error) {
    console.warn('[StorageAdapter] LocalStorage不可用', error)
    return false
  }
}

const ensureAvailability = (): StorageError | null => {
  if (!isLocalStorageAvailable()) {
    return createStorageError(
      StorageErrorCode.UNAVAILABLE,
      '当前环境不支持LocalStorage'
    )
  }

  return null
}

const toSerializableContent = (content: Content): SerializableContent => {
  return {
    ...content,
    createdAt: content.createdAt.toISOString(),
    updatedAt: content.updatedAt.toISOString()
  }
}

const reviveContent = (payload: SerializableContent): Content => {
  const revived = {
    ...payload,
    createdAt: reviveDate(payload.createdAt),
    updatedAt: reviveDate(payload.updatedAt)
  } as Content

  return revived
}

const reviveDate = (value: string | Date): Date => {
  if (value instanceof Date) {
    return value
  }

  if (typeof value === 'string' && ISO_DATE_PATTERN.test(value)) {
    return new Date(value)
  }

  return new Date(value)
}

const readJSON = <T>(key: string): StorageResult<T | null> => {
  const availabilityError = ensureAvailability()
  if (availabilityError) {
    return { ok: false, error: availabilityError }
  }

  try {
    const raw = window.localStorage.getItem(key)
    if (!raw) {
      return { ok: true, data: null }
    }

    const data = JSON.parse(raw, (parseKey, value) => {
      if (
        typeof value === 'string' &&
        DATE_KEYS.has(parseKey) &&
        ISO_DATE_PATTERN.test(value)
      ) {
        return new Date(value)
      }
      return value
    }) as T

    return { ok: true, data }
  } catch (error) {
    console.error(`[StorageAdapter] 读取键 ${key} 失败`, error)
    window.localStorage.removeItem(key)
    return {
      ok: false,
      error: createStorageError(
        StorageErrorCode.DESERIALIZATION_FAILED,
        '解析存储数据失败，已清理损坏数据',
        error
      )
    }
  }
}

const writeJSON = (key: string, value: unknown): StorageResult<void> => {
  const availabilityError = ensureAvailability()
  if (availabilityError) {
    return { ok: false, error: availabilityError }
  }

  try {
    const serialized = JSON.stringify(value, (_k, v) => {
      if (v instanceof Date) {
        return v.toISOString()
      }
      return v
    })
    window.localStorage.setItem(key, serialized)
    return { ok: true, data: undefined }
  } catch (error) {
    console.error(`[StorageAdapter] 写入键 ${key} 失败`, error)

    if (error instanceof TypeError) {
      return {
        ok: false,
        error: createStorageError(
          StorageErrorCode.SERIALIZATION_FAILED,
          '序列化内容时发生错误',
          error
        )
      }
    }

    return {
      ok: false,
      error: mapExceptionToStorageError(error)
    }
  }
}

const updateRecentEntries = (entry: RecentContentEntry): StorageResult<void> => {
  const listResult = readJSON<RecentContentEntry[]>(RECENT_DOCUMENTS_KEY)
  if (!listResult.ok) {
    return listResult
  }

  const entries = listResult.data ?? []
  const filtered = entries.filter(item => item.id !== entry.id)
  filtered.unshift(entry)
  const limited = filtered.slice(0, DEFAULT_RECENT_LIMIT)

  return writeJSON(RECENT_DOCUMENTS_KEY, limited)
}

const removeRecentEntry = (id: string): StorageResult<void> => {
  const listResult = readJSON<RecentContentEntry[]>(RECENT_DOCUMENTS_KEY)
  if (!listResult.ok) {
    return listResult
  }

  const entries = listResult.data ?? []
  const filtered = entries.filter(item => item.id !== id)

  return writeJSON(RECENT_DOCUMENTS_KEY, filtered)
}

const updateMeta = (): StorageResult<void> => {
  return writeJSON(STORAGE_META_KEY, {
    version: STORAGE_VERSION,
    updatedAt: new Date().toISOString()
  })
}

const estimateNamespaceUsage = (): StorageResult<StorageUsageSummary> => {
  const availabilityError = ensureAvailability()
  if (availabilityError) {
    return { ok: false, error: availabilityError }
  }

  try {
    const encoder = typeof TextEncoder !== 'undefined' ? new TextEncoder() : null
    let usedBytes = 0
    let itemCount = 0

    for (let i = 0; i < window.localStorage.length; i++) {
      const key = window.localStorage.key(i)
      if (key && key.startsWith(`${STORAGE_PREFIX}:`)) {
        const value = window.localStorage.getItem(key) ?? ''
        if (encoder) {
          usedBytes += encoder.encode(key).length + encoder.encode(value).length
        } else {
          usedBytes += key.length + value.length
        }
        itemCount += 1
      }
    }

    return {
      ok: true,
      data: {
        usedBytes,
        itemCount
      }
    }
  } catch (error) {
    return {
      ok: false,
      error: mapExceptionToStorageError(error)
    }
  }
}

export const localStorageAdapter: StorageAdapter = {
  saveContent(content) {
    const key = buildContentKey(content.type, content.id)

    const envelope: StoredContentEnvelope = {
      id: content.id,
      type: content.type,
      version: STORAGE_VERSION,
      payload: toSerializableContent(content),
      metadata: {
        savedAt: new Date().toISOString(),
        savedBy: SAVED_BY
      }
    }

    const writeResult = writeJSON(key, envelope)
    if (!writeResult.ok) {
      return writeResult
    }

    const recentResult = updateRecentEntries({
      id: content.id,
      title: content.title,
      type: content.type,
      savedAt: envelope.metadata.savedAt
    })

    if (!recentResult.ok) {
      return recentResult
    }

    const metaResult = updateMeta()
    if (!metaResult.ok) {
      return metaResult
    }

    return { ok: true, data: undefined }
  },

  getContentById(id) {
    const availabilityError = ensureAvailability()
    if (availabilityError) {
      return { ok: false, error: availabilityError }
    }

    const keys = Object.values(ContentType).map(type => buildContentKey(type, id))

    for (const key of keys) {
      const result = readJSON<StoredContentEnvelope>(key)
      if (!result.ok) {
        return { ok: false, error: result.error }
      }

      const envelope = result.data
      if (envelope) {
        const payloadWithType = {
          ...envelope.payload,
          type: envelope.type
        } as SerializableContent
        const content = reviveContent(payloadWithType)
        return { ok: true, data: content }
      }
    }

    return { ok: true, data: null }
  },

  removeContent(id) {
    const availabilityError = ensureAvailability()
    if (availabilityError) {
      return { ok: false, error: availabilityError }
    }

    try {
      const keysToRemove: string[] = []

      for (let i = 0; i < window.localStorage.length; i++) {
        const key = window.localStorage.key(i)
        if (key && key.includes(`:content:`) && key.endsWith(`:${id}`)) {
          keysToRemove.push(key)
        }
      }

      keysToRemove.forEach(key => window.localStorage.removeItem(key))

      const recentResult = removeRecentEntry(id)
      if (!recentResult.ok) {
        return recentResult
      }

      return { ok: true, data: undefined }
    } catch (error) {
      console.error('[StorageAdapter] 删除内容失败', error)
      return {
        ok: false,
        error: mapExceptionToStorageError(error)
      }
    }
  },

  listRecent(limit = DEFAULT_RECENT_LIMIT) {
    const listResult = readJSON<RecentContentEntry[]>(RECENT_DOCUMENTS_KEY)
    if (!listResult.ok) {
      return listResult
    }

    const entries = listResult.data ?? []
    return { ok: true, data: entries.slice(0, limit) }
  },

  getContents(query) {
    const availabilityError = ensureAvailability()
    if (availabilityError) {
      return { ok: false, error: availabilityError }
    }

    try {
      const items: ContentListItem[] = []

      // 遍历所有存储的内容
      for (let i = 0; i < window.localStorage.length; i++) {
        const key = window.localStorage.key(i)
        if (!key || !key.includes(':content:')) {
          continue
        }

        const result = readJSON<StoredContentEnvelope>(key)
        if (!result.ok || !result.data) {
          continue
        }

        const envelope = result.data
        const content = envelope.payload

        // 类型过滤
        if (query?.type && !query.type.includes(envelope.type)) {
          continue
        }

        // 构建列表项
        const wordCount = envelope.type === ContentType.TEXT_DOCUMENT
          ? (content.data as any).wordCount || 0
          : 0

        const preview = envelope.type === ContentType.TEXT_DOCUMENT
          ? ((content.data as any).content || '').substring(0, 100)
          : undefined

        items.push({
          id: content.id,
          title: content.title,
          type: envelope.type,
          status: content.status,
          createdAt: reviveDate(content.createdAt),
          updatedAt: reviveDate(content.updatedAt),
          wordCount,
          preview
        })
      }

      // 排序
      if (query?.sortBy) {
        items.sort((a, b) => {
          let comparison = 0

          switch (query.sortBy) {
            case 'updatedAt':
              comparison = b.updatedAt.getTime() - a.updatedAt.getTime()
              break
            case 'createdAt':
              comparison = b.createdAt.getTime() - a.createdAt.getTime()
              break
            case 'title':
              comparison = a.title.localeCompare(b.title)
              break
          }

          return query.sortOrder === 'asc' ? -comparison : comparison
        })
      }

      // 限制数量
      const limited = query?.limit ? items.slice(0, query.limit) : items

      return { ok: true, data: limited }
    } catch (error) {
      console.error('[StorageAdapter] 获取文档列表失败', error)
      return {
        ok: false,
        error: createStorageError(
          StorageErrorCode.UNKNOWN,
          '加载文档列表失败',
          error
        )
      }
    }
  },

  clear() {
    const availabilityError = ensureAvailability()
    if (availabilityError) {
      return { ok: false, error: availabilityError }
    }

    try {
      const keysToRemove: string[] = []

      for (let i = 0; i < window.localStorage.length; i++) {
        const key = window.localStorage.key(i)
        if (key && key.startsWith(`${STORAGE_PREFIX}:`)) {
          keysToRemove.push(key)
        }
      }

      keysToRemove.forEach(key => window.localStorage.removeItem(key))
      return { ok: true, data: undefined }
    } catch (error) {
      return {
        ok: false,
      error: mapExceptionToStorageError(error)
    }
  }
  },

  getNamespaceUsage() {
    return estimateNamespaceUsage()
  }
}

export default localStorageAdapter
